-- Copyright (c) 2025 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local lu = require 'luaunit'
local port_property_listen = require 'device.class.nic_mgmt.port.port_property_listen'
local context = require 'mc.context'
local comm_fun = require 'device.class.nic_mgmt.comm_fun'
local custom_messages = require 'messages.custom'

TEST_port_set_lldp_enable = {}

-- 创建mock的ORM对象
local function create_mock_orm_obj()
    local obj = {
        NodeId = 'TestPort1',
        NetworkAdapterId = 'TestCard1',
        PortID = 0,
        device_path = '/test/device/path',
        LinkStatusNumeric = 1,
        log_lldp_operation = function() end,
        set_link_status = function() end,
        on_property_changed = {},
        next_tick = function() end
    }
    obj.connect_signal = function(self, signal, callback)
        if signal == obj.on_property_changed then
            obj._property_changed_callback = callback
        end
    end
    obj['bmc.kepler.Systems.NetworkPort'] = {}
    obj['bmc.kepler.Systems.NetworkPort'].property_before_change = {}
    return obj
end

-- 测试device_path为nil时的错误处理
function TEST_port_set_lldp_enable:test_set_lldp_tx_enabled_device_path_nil()
    local original_get_context = context.get_context
    local original_ConfigPortLLDPErr = custom_messages.ConfigPortLLDPErr
    local log_called = false
    local lldp_callback

    local mock_ctx = {
        is_empty = function() return false end,
        get_initiator = function() return 'test_user' end
    }
    context.get_context = function() return mock_ctx end
    custom_messages.ConfigPortLLDPErr = function()
        return 'ConfigPortLLDPErr'
    end

    local orm_obj = create_mock_orm_obj()
    orm_obj.device_path = nil
    orm_obj.log_lldp_operation = function(self, value, ctx, success)
        lu.assertEquals(success, false)
        log_called = true
    end
    orm_obj.connect_signal = function(self, signal, callback)
        if signal == self['bmc.kepler.Systems.NetworkPort'].property_before_change then
            lldp_callback = callback
        end
    end

    local bus = {}
    port_property_listen.register_property_changed_callback(orm_obj, bus)

    local ok = pcall(function()
        lldp_callback('LLDPEnabled', true)
    end)

    lu.assertIsFalse(ok)
    lu.assertIsTrue(log_called)

    context.get_context = original_get_context
    custom_messages.ConfigPortLLDPErr = original_ConfigPortLLDPErr
end

-- 测试获取device_obj失败时的错误处理
function TEST_port_set_lldp_enable:test_set_lldp_tx_enabled_device_obj_nil()
    local original_get_context = context.get_context
    local original_get_device_obj = comm_fun.get_device_obj_by_path_interface
    local original_ConfigPortLLDPErr = custom_messages.ConfigPortLLDPErr
    local log_called = false
    local lldp_callback

    local mock_ctx = {
        is_empty = function() return false end,
        get_initiator = function() return 'test_user' end
    }
    context.get_context = function() return mock_ctx end
    comm_fun.get_device_obj_by_path_interface = function()
        return nil
    end
    custom_messages.ConfigPortLLDPErr = function()
        return 'ConfigPortLLDPErr'
    end

    local orm_obj = create_mock_orm_obj()
    orm_obj.log_lldp_operation = function(self, value, ctx, success)
        lu.assertEquals(success, false)
        log_called = true
    end
    orm_obj.connect_signal = function(self, signal, callback)
        if signal == self['bmc.kepler.Systems.NetworkPort'].property_before_change then
            lldp_callback = callback
        end
    end

    local bus = {}
    port_property_listen.register_property_changed_callback(orm_obj, bus)

    local ok = pcall(function()
        lldp_callback('LLDPEnabled', true)
    end)

    lu.assertIsFalse(ok)
    lu.assertIsTrue(log_called)

    context.get_context = original_get_context
    comm_fun.get_device_obj_by_path_interface = original_get_device_obj
    custom_messages.ConfigPortLLDPErr = original_ConfigPortLLDPErr
end

-- 测试调用SetLLDPTxEnable方法抛出异常时的错误处理
function TEST_port_set_lldp_enable:test_set_lldp_tx_enabled_call_method_error()
    local original_get_context = context.get_context
    local original_get_device_obj = comm_fun.get_device_obj_by_path_interface
    local original_ConfigPortLLDPErr = custom_messages.ConfigPortLLDPErr
    local log_called = false
    local lldp_callback

    local mock_ctx = {
        is_empty = function() return false end,
        get_initiator = function() return 'test_user' end
    }
    context.get_context = function() return mock_ctx end

    local mock_device_obj = {
        call_method = function()
            error('mock error')
        end
    }
    comm_fun.get_device_obj_by_path_interface = function()
        return mock_device_obj
    end
    custom_messages.ConfigPortLLDPErr = function()
        return 'ConfigPortLLDPErr'
    end

    local orm_obj = create_mock_orm_obj()
    orm_obj.log_lldp_operation = function(self, value, ctx, success)
        lu.assertEquals(success, false)
        log_called = true
    end
    orm_obj.connect_signal = function(self, signal, callback)
        if signal == self['bmc.kepler.Systems.NetworkPort'].property_before_change then
            lldp_callback = callback
        end
    end

    local bus = {}
    port_property_listen.register_property_changed_callback(orm_obj, bus)

    local ok = pcall(function()
        lldp_callback('LLDPEnabled', true)
    end)

    lu.assertIsFalse(ok)
    lu.assertIsTrue(log_called)

    context.get_context = original_get_context
    comm_fun.get_device_obj_by_path_interface = original_get_device_obj
    custom_messages.ConfigPortLLDPErr = original_ConfigPortLLDPErr
end

-- 测试SetLLDPTxEnable方法返回false时的错误处理
function TEST_port_set_lldp_enable:test_set_lldp_tx_enabled_call_method_return_false()
    local original_get_context = context.get_context
    local original_get_device_obj = comm_fun.get_device_obj_by_path_interface
    local original_ConfigPortLLDPErr = custom_messages.ConfigPortLLDPErr
    local log_called = false
    local lldp_callback

    local mock_ctx = {
        is_empty = function() return false end,
        get_initiator = function() return 'test_user' end
    }
    context.get_context = function() return mock_ctx end

    local mock_device_obj = {
        call_method = function()
            return false
        end
    }
    comm_fun.get_device_obj_by_path_interface = function()
        return mock_device_obj
    end
    custom_messages.ConfigPortLLDPErr = function()
        return 'ConfigPortLLDPErr'
    end

    local orm_obj = create_mock_orm_obj()
    orm_obj.log_lldp_operation = function(self, value, ctx, success)
        lu.assertEquals(success, false)
        log_called = true
    end
    orm_obj.connect_signal = function(self, signal, callback)
        if signal == self['bmc.kepler.Systems.NetworkPort'].property_before_change then
            lldp_callback = callback
        end
    end

    local bus = {}
    port_property_listen.register_property_changed_callback(orm_obj, bus)

    local ok = pcall(function()
        lldp_callback('LLDPEnabled', true)
    end)

    lu.assertIsFalse(ok)
    lu.assertIsTrue(log_called)

    context.get_context = original_get_context
    comm_fun.get_device_obj_by_path_interface = original_get_device_obj
    custom_messages.ConfigPortLLDPErr = original_ConfigPortLLDPErr
end

-- 测试成功启用LLDP TX
function TEST_port_set_lldp_enable:test_set_lldp_tx_enabled_success_enable()
    local original_get_context = context.get_context
    local original_get_device_obj = comm_fun.get_device_obj_by_path_interface
    local method_called = false
    local enable_value = nil
    local log_success_called = false
    local lldp_callback

    local mock_ctx = {
        is_empty = function() return false end,
        get_initiator = function() return 'test_user' end
    }
    context.get_context = function() return mock_ctx end

    local mock_device_obj = {
        call_method = function(self, method_name, param_type, value)
            lu.assertEquals(method_name, 'SetLLDPTxEnable')
            lu.assertEquals(param_type, 'b')
            method_called = true
            enable_value = value
            return true
        end
    }
    comm_fun.get_device_obj_by_path_interface = function(bus, path, interface)
        lu.assertEquals(path, '/test/device/path')
        return mock_device_obj
    end

    local orm_obj = create_mock_orm_obj()
    orm_obj.log_lldp_operation = function(self, value, ctx, success)
        if success then
            log_success_called = true
        end
    end
    orm_obj.connect_signal = function(self, signal, callback)
        if signal == self['bmc.kepler.Systems.NetworkPort'].property_before_change then
            lldp_callback = callback
        end
    end

    local bus = {}
    port_property_listen.register_property_changed_callback(orm_obj, bus)
    lldp_callback('LLDPEnabled', true)

    lu.assertIsTrue(method_called)
    lu.assertEquals(enable_value, true)
    lu.assertIsTrue(log_success_called)

    context.get_context = original_get_context
    comm_fun.get_device_obj_by_path_interface = original_get_device_obj
end

-- 测试成功禁用LLDP TX
function TEST_port_set_lldp_enable:test_set_lldp_tx_enabled_success_disable()
    local original_get_context = context.get_context
    local original_get_device_obj = comm_fun.get_device_obj_by_path_interface
    local method_called = false
    local enable_value = nil
    local log_success_called = false
    local lldp_callback

    local mock_ctx = {
        is_empty = function() return false end,
        get_initiator = function() return 'test_user' end
    }
    context.get_context = function() return mock_ctx end

    local mock_device_obj = {
        call_method = function(self, method_name, param_type, value)
            method_called = true
            enable_value = value
            return true
        end
    }
    comm_fun.get_device_obj_by_path_interface = function()
        return mock_device_obj
    end

    local orm_obj = create_mock_orm_obj()
    orm_obj.log_lldp_operation = function(self, value, ctx, success)
        if success then
            log_success_called = true
        end
    end
    orm_obj.connect_signal = function(self, signal, callback)
        if signal == self['bmc.kepler.Systems.NetworkPort'].property_before_change then
            lldp_callback = callback
        end
    end

    local bus = {}
    port_property_listen.register_property_changed_callback(orm_obj, bus)
    lldp_callback('LLDPEnabled', false)

    lu.assertIsTrue(method_called)
    lu.assertEquals(enable_value, false)
    lu.assertIsTrue(log_success_called)

    context.get_context = original_get_context
    comm_fun.get_device_obj_by_path_interface = original_get_device_obj
end

-- 测试有NetworkPort接口时注册回调
function TEST_port_set_lldp_enable:test_register_callback_with_interface()
    local orm_obj = create_mock_orm_obj()
    local on_property_changed_connected = false
    local property_before_change_connected = false

    orm_obj.connect_signal = function(self, signal, callback)
        if signal == self.on_property_changed then
            on_property_changed_connected = true
        elseif signal == self['bmc.kepler.Systems.NetworkPort'].property_before_change then
            property_before_change_connected = true
        end
    end

    local bus = {}
    port_property_listen.register_property_changed_callback(orm_obj, bus)

    lu.assertIsTrue(on_property_changed_connected)
    lu.assertIsTrue(property_before_change_connected)
end

-- 测试无NetworkPort接口时注册回调
function TEST_port_set_lldp_enable:test_register_callback_without_interface()
    local orm_obj = create_mock_orm_obj()
    orm_obj['bmc.kepler.Systems.NetworkPort'] = nil
    local on_property_changed_connected = false
    local property_before_change_connected = false

    orm_obj.connect_signal = function(self, signal, callback)
        if signal == self.on_property_changed then
            on_property_changed_connected = true
        end
        if self['bmc.kepler.Systems.NetworkPort'] and
           signal == self['bmc.kepler.Systems.NetworkPort'].property_before_change then
            property_before_change_connected = true
        end
    end

    local bus = {}
    port_property_listen.register_property_changed_callback(orm_obj, bus)

    lu.assertIsTrue(on_property_changed_connected)
    lu.assertIsFalse(property_before_change_connected)
end

return TEST_port_set_lldp_enable

